package com.hera.base.dao.repository;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import com.hera.base.util.FiltroDTO;
import com.hera.base.util.ParametroDTO;

public class BaseRepositoryImpl<T, ID extends Serializable>
	extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {

	private EntityManager entityManager;
	protected Class<T> domainClass;

	static final Logger logger = Logger.getLogger(BaseRepositoryImpl.class);

	
	
	public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
		super(domainClass, entityManager);
		// This is the recommended method for accessing inherited class dependencies.
		this.entityManager = entityManager;
		this.domainClass=domainClass;
		
		
	}


	@SuppressWarnings("unchecked")
	public List<T> ejecutarHQL(String hql, List<Object> params){
		System.out.println("query "  + hql);
		System.out.println("params "  + params);
          
		Query query = entityManager.createQuery(hql);
		if(params != null){
			for(int i=0; i<params.size(); i++){
				System.out.println("set params "  + i +" en: " + params.get(i));
				query.setParameter(i+1, params.get(i));
			}
		}
	
		return query.getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> ejecutarNativeSQL(String sql, List<Object> params){
		System.out.println("query "  + sql);
		System.out.println("params "  + params);
          
		Query query = entityManager.createNativeQuery(sql);
		if(params != null){
			for(int i=0; i<params.size(); i++){
				System.out.println("set params "  + i +" en: " + params.get(i));
				query.setParameter(i+1, params.get(i));
			}
		}
	
		return query.getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public void ejecutarUpdateNativeSQL(String sql, List<Object> params){
		System.out.println("query "  + sql);
		System.out.println("params "  + params);
          
		Query query = entityManager.createNativeQuery(sql);
		if(params != null){
			for(int i=0; i<params.size(); i++){
				System.out.println("set params "  + i +" en: " + params.get(i));
				query.setParameter(i+1, params.get(i));
			}
		}
	
		query.executeUpdate();
	}
	
	public List<T> obtenerEntidadesPorFiltros(FiltroDTO filtroDTO) {
		Session session = entityManager.unwrap(Session.class);	
		Criteria criteria = session.createCriteria(domainClass);
		List<String> values=filtroDTO.getAliasDTO();
		HashMap<String, String> mAlias=new HashMap<String, String>();
		for(String alias:values){
			criteria=criteria.createAlias(alias, alias);			
		}
		logger.info("Inicio setear parametros");
		for (ParametroDTO parametroDTO : filtroDTO.getFiltro()) {
			if (parametroDTO.getValorParametro() == null || parametroDTO.getValorParametro().equals("")) {
				logger.info("Parametro Excluido > " + parametroDTO.getNombreParametro() + " : " + parametroDTO.getValorParametro());
				continue;
			}
			if (parametroDTO.getTipoParametro().equals(ParametroDTO.TIPO_IGUAL)) {
				logger.info("Parametro incluido igual > " + parametroDTO.getNombreParametro() + " : " + parametroDTO.getValorParametro()+" "+parametroDTO.getTipoDato());
				criteria.add(Restrictions.eq(parametroDTO.getNombreParametro(), parametroDTO.getValorParametro()));
			} else if (parametroDTO.getTipoParametro().equals(ParametroDTO.TIPO_LIKE)) {
				logger.info("Parametro incluido Like > " + parametroDTO.getNombreParametro() + " : " + parametroDTO.getValorParametro());
				criteria.add(Restrictions.like(parametroDTO.getNombreParametro(), parametroDTO.getValorParametro() + "%").ignoreCase());
			}
		}
		logger.info("Fin setear parametros");

		logger.info("Inicio ordenamiento");
		for (ParametroDTO parametroDTO : filtroDTO.getOrdenamiento()) {
			if (parametroDTO.getOrdenamiento().equals(ParametroDTO.ORDEN_ASCENDENTE)) {
				logger.info("Orden > " + parametroDTO.getNombreParametro() + " : ASC ");
				criteria.addOrder(Order.asc(parametroDTO.getNombreParametro()));
			} else {
				logger.info("Orden > " + parametroDTO.getNombreParametro() + " : DESC ");
				criteria.addOrder(Order.desc(parametroDTO.getNombreParametro()));
			}
		}
		logger.info("Fin ordenamiento");
		return criteria.list();
	}
}


